package com.example.glblend;

import androidx.appcompat.app.AppCompatActivity;

import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.SurfaceTexture;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;

import java.io.IOException;
import java.util.List;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class MainActivity extends AppCompatActivity implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener, Runnable, android.hardware.Camera.AutoFocusCallback {

    private static final String TAG = "MainActivity";
    
    private GLSurfaceView glSurfaceView;

    private Image image;

    private ImageShaderProgram imageShaderProgram;

    private int textureId;

    private Camera camera;

    private CameraShaderProgram cameraShaderProgram;

    private android.hardware.Camera mCamera;

    private int width = 1920, height = 1080;

    private SurfaceTexture surfaceTexture;

    private int textureOES;

    private float[] projectionMatrix = new float[16];

    private float[] finalMatrix = new float[16];

    private float[] modelMatrix = new float[16];

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        glSurfaceView = findViewById(R.id.gl_view);
        glSurfaceView.setEGLContextClientVersion(2);
        glSurfaceView.setRenderer(this);
        glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
    }

    @Override
    protected void onPause() {
        super.onPause();
        glSurfaceView.onPause();
        closeCamera();
        if (surfaceTexture != null) {
            surfaceTexture.release();
            surfaceTexture = null;
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        glSurfaceView.onResume();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{Manifest.permission.CAMERA}, 0);
            } else {
                openCamera();
            }
        } else {
            openCamera();
        }
    }

    private void openCamera() {
        mCamera = android.hardware.Camera.open(android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK);
        android.hardware.Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewSize(width, height);
        List<String> focusModes = parameters.getSupportedFocusModes();
        if (focusModes.contains("auto")) {
            Log.d(TAG, "auto mode");
            parameters.setFocusMode("auto");
        }
        mCamera.setParameters(parameters);
        mCamera.setDisplayOrientation(0);
        try {
            if (surfaceTexture != null) {
                mCamera.stopPreview();
                mCamera.setPreviewTexture(surfaceTexture);
                mCamera.startPreview();
                mCamera.autoFocus(this);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void closeCamera() {
        Log.d(TAG, "closeCamera: ");
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
//        GLES20.glEnable(GLES20.GL_DEPTH_TEST);

        GLES20.glEnable(GLES20.GL_BLEND);
        GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);

        image = new Image();
        imageShaderProgram = new ImageShaderProgram(this);

        textureId = TextureHelper.loadTexture(this, R.drawable.lyf);

        camera = new Camera();
        cameraShaderProgram = new CameraShaderProgram(this);

        textureOES = TextureHelper.loadTextureOES();
        surfaceTexture = new SurfaceTexture(textureOES);
        surfaceTexture.setOnFrameAvailableListener(this);
        if (mCamera != null) {
            try {
                mCamera.stopPreview();
                mCamera.setPreviewTexture(surfaceTexture);
                mCamera.startPreview();
                mCamera.autoFocus(this);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0, 0, width, height);

        Matrix.setIdentityM(modelMatrix, 0);
        Matrix.rotateM(modelMatrix, 0, -90, 0, 0, 1);

    }

    @Override
    public void onDrawFrame(GL10 gl) {
        GLES20.glClearColor(1, 0 , 0, 1);
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

        imageShaderProgram.useProgram();
        imageShaderProgram.setUniform(textureId);

        image.bindData(imageShaderProgram);
        image.draw();


        cameraShaderProgram.useProgram();
        cameraShaderProgram.setUniform(modelMatrix, textureOES);

        camera.bindData(cameraShaderProgram);
        camera.draw();

        surfaceTexture.updateTexImage();
    }

    @Override
    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
        glSurfaceView.requestRender();
    }

    @Override
    public void run() {
        if (mCamera != null) {
            mCamera.autoFocus(this);
        }
    }

    @Override
    public void onAutoFocus(boolean success, android.hardware.Camera camera) {
        glSurfaceView.postDelayed(this, 1500);
    }
}